home *** CD-ROM | disk | FTP | other *** search
/ PD ROM 1 / PD ROM Volume I - Macintosh Software from BMUG (1988).iso / Programming / Programming Tools / Pascal Demos from Apple / scroll example / SCROLL.TEXT < prev    next >
Encoding:
Text File  |  1985-02-05  |  17.3 KB  |  398 lines  |  [TEXT/ttxt]

  1. {$X-}
  2. {$R-}
  3. PROGRAM Scroll;
  4. {------------------------------------------------------------------------------------
  5.      This is a simple program to demonstrate how to use scroll bars.
  6.      You can scroll text or graphics or both.
  7.      You can scroll horizontally or vertically.
  8.      By Cary Clark, Macintosh Technical Support
  9.      Copyright Apple Computer Inc., 1984
  10.  -----------------------------------------------------------------------------------}
  11.  
  12.    USES
  13.       {$U-}
  14.       {$U Obj/MemTypes  } MemTypes,
  15.       {$U Obj/QuickDraw } QuickDraw,
  16.       {$U Obj/OSIntf    } OSIntf,
  17.       {$U Obj/ToolIntf  } ToolIntf;
  18.  
  19.    CONST
  20.       Horizontal =       1; {These are the choices in the menu 'Scroll Bar'}
  21.       Vertical =         2;
  22.       TextItem =         4;
  23.       Graphics =         5;
  24.  
  25.       FileMenu =         1; {Resource numbers and position in the Menu bar}
  26.       ScrollMenu =       2;
  27.  
  28.       NumOfRects =      30; {quantity of rectangles and strings to scroll around}
  29.       NumOfStrings =    55;
  30.  
  31.    TYPE
  32.       MyRectData =      ARRAY [1..NumOfRects] OF Rect; {Graphics structure: }
  33.       MyRectPtr =       ^MyRectData;                   { an array of rectangles}
  34.       MyRectHdl =       ^MyRectPtr;
  35.  
  36.    VAR
  37.       hTE:              TEHandle;      {TextEdit handle}
  38.       hScroll,                         {Horizontal scroll bar}
  39.       vScroll:          ControlHandle; {Vertical scroll bar}
  40.       MyWindow:         WindowPtr;     {Document window}
  41.       hdlScrollMenu:    MenuHandle;    {Handle to the menu items}
  42.       MyRect:           MyRectHdl;     {Handle to array of rectangles}
  43.       originalPart:     INTEGER;       {1st part of the scroll bar hit}
  44.       PageCorner,                      {Location of the upper left hand page corner}
  45.       EventPoint:       Point;         {Where an event took place}
  46.       growBoxRect,                     {area of the window reserved for the grow box}
  47.       MyViewRect:       Rect;          {display rectangle containing scrollable data}
  48.       doneFlag,                        {Set TRUE when the user selects 'Quit'}
  49.       showText,                        {Set TRUE when text can be scrolled}
  50.       showGraphics:     BOOLEAN;       {Set TRUE when graphics can be scrolled}
  51.  
  52. {-----------------------------------------------------------------------------------}
  53.  
  54.    PROCEDURE SetUpData;
  55.  
  56. {This procedure initializes two data structures; a TextEdit record and an array of
  57.  rectangles.  Initially, only text and the vertical scrollbar will be displayed.}
  58.  
  59.       VAR
  60.          MyString:      StringHandle;  {Temporary container for a string in the
  61.                                        resource fork}
  62.          counter:       INTEGER;       {Counters must be local to the procedure}
  63.          destRect:      Rect;          {Rectangle containing the larger-than-the-
  64.                                        screen page}
  65.  
  66.       BEGIN
  67. {The TextEdit record is initialized by reading in a string from the application's
  68. resource fork and then inserting it a number of times into the TextEdit record.}
  69.          MyString := GetString(256);   {Get some text to play around with}
  70.  
  71. {Set the view as the portrect less the vertical scrollbar area.  The TextEdit
  72. destRect will be set to the current window width plus an arbitrary value.}
  73.          MyViewRect := MyWindow^.portrect;
  74.          destRect := MyViewRect;
  75.          destRect.right := destRect.right + 300;
  76.          PageCorner.h := - destRect.left;
  77.          PageCorner.v := - destRect.top;
  78.          MyViewRect.right := MyViewRect.right - 15; {subtract width of scrollbar}
  79.          hTE := TENew(destRect, MyViewRect);
  80.  
  81.          HLock(Pointer(MyString)); {Can't move if we are going to point to the text}
  82.          FOR counter := 1 TO NumOfStrings DO {Create a TE record full of the string.}
  83.             TEInsert(Pointer(Ord4(MyString^) + 1), {past the string's length byte}
  84.              Length(MyString^^), hTE);
  85.          HUnLock(Pointer(MyString)); {Free to move again}
  86.  
  87.          {Now, create a structure of rectangles.}
  88.          MyRect := Pointer(NewHandle(Sizeof(MyRectData))); {240 bytes }
  89.          FOR counter := 1 TO NumOfRects DO
  90.             SetRect(MyRect^^[counter], counter * 23, counter * 20, counter *
  91.              23 + 50, counter * 20 + 50);
  92.  
  93.          showText := TRUE;
  94.          showGraphics := FALSE;
  95.          ShowWindow(MyWindow); {Display the window and the text it contains}
  96.  
  97.          vScroll := GetNewControl(256, MyWindow); {vertical scrollbar}
  98.          hScroll := GetNewControl(257, MyWindow); {horizontal scrollbar, not shown}
  99.          SetRect(growBoxRect, vScroll^^.contrlRect.left+1,
  100.           vScroll^^.contrlRect.bottom+1, myWindow^.portRect.right,
  101.           myWindow^.portRect.bottom); {This area is set up for ValidRect, below.}
  102.  
  103.          CheckItem(hdlScrollMenu, Vertical, TRUE);
  104.          CheckItem(hdlScrollMenu, TextItem, TRUE)
  105.       END; {of SetUpData}
  106.  
  107. {------------------------------------------------------------------------------------}
  108.  
  109.    PROCEDURE GrafUpdate(whatpart: Rect);
  110. {This is roughly the equivalent of what TEUpdate does with text.  The upper left hand
  111. corner of the page is moved up and to the left to simulate a view further down and
  112. to the right.  To more accurately resemble a Toolbox routine like TEUpdate, this
  113. procedure should also preserve the current clip region and origin.}
  114.  
  115.       VAR
  116.          count:         INTEGER;
  117.          dummyRect:     Rect;
  118.  
  119.       BEGIN
  120.          SetOrigin(PageCorner.h, PageCorner.v); {negative moves the origin left, up}
  121.          OffsetRect(whatpart, PageCorner.h, PageCorner.v); {move the update rect.}
  122.          ClipRect(whatpart); {only redraw the portion that the user requests}
  123.          FOR count := 1 TO NumOfRects DO
  124.            {Redraw the object if it intersects the update rectangle}
  125.             IF SectRect(MyRect^^[count], whatpart, dummyRect)
  126.                THEN FrameRect(MyRect^^[count]);
  127.          SetOrigin(0, 0); {reset the origin back to the upper left hand corner}
  128.          ClipRect(MyWindow^.portrect); {reset the clip region to the entire window}
  129.       END; {of GrafUpdate}
  130.  
  131. {------------------------------------------------------------------------------------}
  132.  
  133.    PROCEDURE ScrollBits;
  134. {This routine scrolls horizontally and vertically both graphics and text.  If you are
  135.  only scrolling text, only the TEScroll is required.  If you are only scrolling
  136.  graphics, then only the ScrollRect and GrafUpDate is needed.}
  137.  
  138.       VAR
  139.          vChange, hChange, vScrollValue, hScrollValue: INTEGER;
  140.          AnUpdateRgn: RgnHandle;
  141.  
  142.       BEGIN
  143.          vScrollValue := GetCtlValue(vScroll); {These values will be used a lot so}
  144.          hScrollValue := GetCtlValue(hScroll); {they are temporary variables.}
  145.  
  146. {find the vertical and horizontal change}
  147.          vChange := PageCorner.v - vScrollValue; {the vertical difference}
  148.          hChange := PageCorner.h - hScrollValue; {the horizontal difference}
  149.  
  150. {record the values for next time}
  151.          PageCorner.v := vScrollValue;
  152.          PageCorner.h := hScrollValue;
  153.  
  154. {for pure text, only a TEScroll is required}
  155.          IF showText AND NOT showGraphics
  156.             THEN TEScroll(hChange, vChange, hTE);
  157.  
  158. {For graphics, a ScrollRect will move the visible bits on the screen.  The
  159. region returned by ScrollRect indicates what part of the window needs to
  160. be updated.}
  161.          IF showGraphics
  162.             THEN BEGIN
  163.                AnUpdateRgn := NewRgn;
  164.                ScrollRect(MyViewRect, hChange, vChange, AnUpdateRgn);
  165.  
  166. {This draws the new text.  The clipping is necessary because normally
  167. TextEdit redraws the entire character height and perhaps only a partial
  168. character scroll was done.  Since TextEdit erases before it draws, the text,
  169. if any, is drawn before the graphics.}
  170.                IF showText
  171.                   THEN
  172.                      WITH hTE^^.destRect DO BEGIN
  173.                         left := - hScrollValue;
  174.                         top := - vScrollValue;
  175.                         ClipRect(AnUpdateRgn^^.rgnbbox);
  176.                         TEUpdate(AnUpdateRgn^^.rgnbbox, hTE);
  177.                         ClipRect(MyWindow^.portrect)
  178.                      END; {of showText}
  179.  
  180.                GrafUpdate(AnUpdateRgn^^.rgnbbox); {Fill in the newly exposed region.}
  181.                DisposeRgn(AnUpdateRgn)
  182.             END {of showGraphics}
  183.       END; {of ScrollBits}
  184.  
  185. {------------------------------------------------------------------------------------}
  186.  
  187.    PROCEDURE TrackScroll(theControl: ControlHandle; partCode: INTEGER);
  188. {This routine adjusts the value of the scrollbar.  A reasonable change would
  189. be to adjust the minimum scroll amount to equal the text's lineheight.}
  190.  
  191.       VAR
  192.          amount,
  193.          StartValue:    INTEGER;
  194.          up:            BOOLEAN;
  195.  
  196.       BEGIN
  197.          up := (partCode = inUpButton) OR (partCode = inPageUp); {TRUE if
  198.             scrolling up}
  199.          StartValue := GetCtlValue(theControl); {the initial control value}
  200.  
  201.          IF
  202. {The scrollbar value is decreased, and it is not already at the minimum.}
  203.            ((up AND (StartValue > GetCtlMin(theControl))) OR
  204. {The scrollbar value is increased, and it is not already at the maximum.}
  205.            ((NOT up) AND (StartValue < GetCtlMax(theControl)))) AND
  206. {to prevent tracking as the page up or down area disappears}
  207.            (originalPart = partCode)
  208.             THEN BEGIN
  209.                IF up
  210.                   THEN
  211.                      amount := - 1
  212.                   ELSE
  213.                      amount := 1; {set the direction}
  214.                IF (partCode = inPageUp) OR (partCode = inPageDown)
  215.                   THEN BEGIN
  216.                      {change the movement to a full page}
  217.                      WITH MyViewRect DO
  218.                         IF theControl = vScroll
  219.                            THEN
  220.                               amount := amount * (bottom - top)
  221.                            ELSE
  222.                               amount := amount * (right - left)
  223.                   END; {of partCode}
  224.                SetCtlValue(theControl, StartValue + amount);
  225.                ScrollBits
  226.             END
  227.       END; {of TrackScroll}
  228.  
  229. {-----------------------------------------------------------------------------------}
  230.  
  231.    PROCEDURE MyControls; {respond to a mouse down event in one of the controls}
  232.  
  233.       VAR
  234.          dummy:         INTEGER;
  235.          theControl:    ControlHandle;
  236.  
  237.       BEGIN  {Get control and part.}
  238.          originalPart := FindControl(EventPoint, MyWindow, theControl);
  239.          IF originalPart = inThumb
  240.             THEN BEGIN
  241. {Thumb is tracked until it is released; then the bits are scrolled.}
  242.                dummy := TrackControl(theControl, EventPoint, NIL);
  243.                ScrollBits
  244.             END {of whichpart}
  245. {For the arrows and the page changes, scroll while the mouse is held down.}
  246.             ELSE
  247.                dummy := TrackControl(theControl, EventPoint, @TrackScroll)
  248.       END; {of Mycontrols}
  249.  
  250. {-----------------------------------------------------------------------------------}
  251.  
  252.    PROCEDURE MainEventLoop;
  253. {Respond to menu selections, the scrollbars, and update events.}
  254.  
  255.       VAR
  256.          myEvent: EventRecord; {All of the information about the event}
  257.          menuResult: LONGINT; {Information returned by MenuSelect}
  258.          theMenu, {Which menu was selected}
  259.          theItem: INTEGER; {Which item within the menu}
  260.          checked: BOOLEAN; {Is the menu item checked}
  261.          MarkChar: Char; {The checkmark character}
  262.          tempWindow: WindowPtr;
  263.          tempRect: Rect;
  264.  
  265.       BEGIN
  266.          REPEAT
  267.             checked := GetNextEvent(everyEvent, myEvent); {checked here is ignored}
  268.             CASE myEvent.what OF
  269.                mouseDown: BEGIN
  270. {the user pressed or is holding the mouse button down}
  271.                   CASE FindWindow(myEvent.where, tempWindow) OF
  272.  
  273.                      inMenuBar: BEGIN {the mouseDown was in the menu bar}
  274.                         menuResult := MenuSelect(myEvent.where);
  275.                         theMenu := HiWord(menuResult);
  276.                         theItem := LoWord(menuResult);
  277.                         CASE theMenu OF
  278.                            FileMenu: doneFlag := TRUE; { Quit }
  279.                            ScrollMenu: BEGIN
  280. {The items in the menu are used to keep track of the user has chosen thus far. These
  281. lines toggle the checkmark in the menu and leave the result in the variable checked.}
  282.                             GetItemMark(hdlScrollMenu, theItem, MarkChar);
  283.                             checked := MarkChar <> Chr(checkmark);
  284.                             CheckItem(hdlScrollMenu, theItem, checked);
  285.  
  286. {Any selection will cause some part of the screen to be redrawn.  The selection that
  287. the user makes causes some part of the screen to become invalid.}
  288.                              IF (theItem = TextItem) OR (theItem = graphicsItem)
  289.                                 THEN BEGIN
  290.                                    InvalRect(MyViewRect);
  291. {The small area between the scrollbars reserved for the grow box should never be
  292. redrawn.}
  293.                                    ValidRect(growBoxRect)
  294.                                 END;
  295.                              CASE theItem OF
  296.  
  297.                               Horizontal: BEGIN
  298.                                InvalRect(hScroll^^.contrlrect);
  299.                                IF checked
  300.                                 THEN BEGIN
  301.                                  ShowControl(hScroll);
  302.                                  MyViewRect.bottom := hScroll^^.contrlrect.top
  303.                                 END {checked}
  304.                                 ELSE BEGIN {not checked}
  305.                                  HideControl(hScroll);
  306.                                  MyViewRect.bottom := hScroll^^.contrlrect.bottom
  307.                                 END {not checked}
  308.                               END; {horizontal}
  309.  
  310.                               Vertical: BEGIN
  311.                                InvalRect(vScroll^^.contrlrect);
  312.                                IF checked
  313.                                 THEN BEGIN
  314.                                  ShowControl(vScroll);
  315.                                  MyViewRect.right := vScroll^^.contrlrect.left
  316.                                 END {checked}
  317.                                 ELSE BEGIN {not checked}
  318.                                  HideControl(vScroll);
  319.                                  MyViewRect.right := vScroll^^.contrlrect.right
  320.                                 END {not checked}
  321.                               END; {vertical}
  322.  
  323.                               TextItem: BEGIN
  324. {Since we have dereferenced the destrect, no calls in the scope of this WITH should
  325. cause a memory compaction.}
  326.                                showText := checked;
  327.                                IF checked
  328.                                 THEN
  329.                                  WITH hTE^^.destRect DO BEGIN
  330.                                   top := - GetCtlValue(vScroll);
  331.                                   left := - GetCtlValue(hScroll);
  332.                                  END {of checked}
  333.                               END; {of textItem}
  334.  
  335.                                graphicsItem: showGraphics := checked;
  336.  
  337.                              END; {of CASE}
  338.                              IF showText
  339.                               THEN hTE^^.viewrect := MyViewRect
  340.                            END {of inMenuBar}
  341.                         END; {of FindWindow CASE}
  342.                         HiliteMenu(0)
  343.                      END; {of mouseDown}
  344.  
  345.                      inContent:
  346. {The rectangles making up the controls are the part of the window outside the view.}
  347.                         BEGIN
  348.                         EventPoint := myEvent.where;
  349.                         GlobalToLocal(EventPoint);
  350.                         IF NOT PtInRect(EventPoint, MyViewRect)
  351.                            THEN MyControls
  352.                      END {in Content}
  353.                   END {of CASE}
  354.                END; {of mouseDown}
  355.  
  356.                updateEvent:
  357. {In response to InvalRects, the appropriate text or graphics is erased and redrawn.
  358. The BeginUpdate causes the VisRgn to be replaced by the intersection of the VisRgn
  359. and the UpdateRgn.}
  360.                   BEGIN
  361.                   BeginUpdate(MyWindow);
  362.                   EraseRect(MyViewRect); {start with a clean slate}
  363.                   IF showText
  364.                      THEN TEUpdate(MyWindow^.VisRgn^^.rgnbbox, hTE);
  365. {Call GrafUpdate with the intersection, if any, of the VisRgn and the view}
  366.                   IF showGraphics AND SectRect(MyWindow^.VisRgn^^.rgnbbox,
  367.                    MyViewRect, tempRect)
  368.                      THEN GrafUpdate(tempRect);
  369.                   EndUpdate(MyWindow)
  370.                END {of updateEvent}
  371.  
  372.             END {of event CASE}
  373.          UNTIL doneFlag
  374.       END;
  375.  
  376. {------------------------------------------------------------------------------------}
  377.  
  378.    BEGIN
  379.       InitGraf(@ThePort); {initialize QuickDraw}
  380.       InitWindows; {initialize Window Manager; clear desktop and menubar}
  381.       InitFonts; {initialize Font Manager}
  382.       FlushEvents(everyEvent, 0); {throw away any stray events}
  383.       TEInit; {initialize TextEdit}
  384.       InitMenus; {initialize Menu Manager}
  385.       hdlScrollMenu := GetMenu(FileMenu); {(hdlScrollMenu is ignored)}
  386.       InsertMenu(hdlScrollMenu, 0);
  387.       hdlScrollMenu := GetMenu(ScrollMenu);
  388.       InsertMenu(hdlScrollMenu, 0);
  389.       DrawMenuBar;
  390.       doneFlag := FALSE; {user 'Quit' flag}
  391.       MyWindow := GetNewWindow(256, NIL, Pointer( - 1)); {get window to work within}
  392.       SetPort(MyWindow); {point to window}
  393.       TextFont(applFont); {select default application font}
  394.       SetUpData; {initialize user data and controls}
  395.       InitCursor; {change the watch into an arrow}
  396.       MainEventLoop {handle events until we are through}
  397.    END.
  398.